package org.bjf.utils;

import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;


/**
 * @author bjf
 */
@Slf4j
public class RetryUtil {

  /**
   * 默认重试机制
   */
  public static <T> Retryer<T> getDefaultRetryer() {

    return RetryerBuilder.<T>newBuilder()
        //抛出runtime异常、checked异常时都会重试，但是抛出error不会重试。
        .retryIfException()
        //尝试次数
        .withStopStrategy(StopStrategies.stopAfterAttempt(3))
        //重试策略 时间间隔3秒，随着重试次数的增加每次递增 1 s
        .withWaitStrategy(
            WaitStrategies.incrementingWait(3, TimeUnit.SECONDS, 1, TimeUnit.SECONDS))
        .withRetryListener(new RetryListener() {
          @Override
          public <V> void onRetry(Attempt<V> attempt) {
            log.debug("retry time = " + attempt.getAttemptNumber());
            if (attempt.hasException()) {
              log.error("try failed", attempt.getExceptionCause());
            }
          }
        })
        .build();
  }

  /**
   * @param times 重试次数
   * @param delay 重新时间间隔
   */
  public static <T> Retryer<T> getRetryer(int times, int delay) {

    return RetryerBuilder.<T>newBuilder()
        //抛出runtime异常、checked异常时都会重试，但是抛出error不会重试。
        .retryIfException()
        //尝试次数
        .withStopStrategy(StopStrategies.stopAfterAttempt(times))
        //重试策略 固定时间间隔3秒
        .withWaitStrategy(WaitStrategies.fixedWait(delay, TimeUnit.SECONDS))
        //重试策略 时间间隔3秒，随着重试次数的增加每次递增 1 s
        //.withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS, 1, TimeUnit.SECONDS))
        .withRetryListener(new RetryListener() {
          @Override
          public <V> void onRetry(Attempt<V> attempt) {
            log.debug("retry time = " + attempt.getAttemptNumber());
            if (attempt.hasException()) {
              log.error("try failed", attempt.getExceptionCause());
            }
          }
        })
        .build();
  }

  /**
   * @param retryValue 指定重试的值
   * @param times 重试次数
   * @param delay 重新时间间隔
   */
  public static <T> Retryer<T> getRetryer(T retryValue, int times, int delay) {

    return RetryerBuilder.<T>newBuilder()
        //抛出runtime异常、checked异常时都会重试，但是抛出error不会重试。
        .retryIfException()
        //返回指定值也需要重试
        .retryIfResult(Predicates.equalTo(retryValue))
        //尝试次数
        .withStopStrategy(StopStrategies.stopAfterAttempt(times))
        //重试策略 固定时间间隔3秒
        .withWaitStrategy(WaitStrategies.fixedWait(delay, TimeUnit.SECONDS))
        //重试策略 时间间隔3秒，随着重试次数的增加每次递增 1 s
        //.withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS, 1, TimeUnit.SECONDS))
        .withRetryListener(new RetryListener() {
          @Override
          public <V> void onRetry(Attempt<V> attempt) {
            log.debug("retry time = " + attempt.getAttemptNumber());
            if (attempt.hasException()) {
              log.error("try failed", attempt.getExceptionCause());
            }
          }
        })
        .build();
  }

  public static void main(String[] args) {
    try {
      RetryUtil.getRetryer(0L, 3, 3)
          .call(() -> {
            Long val = 99L;
            return val;});
    } catch (Exception e) {
      log.error(e.getMessage(),e);
    }

    // spring retry 解决方案
  }

}